
// x86.c: Builds Intel x86 machine code.

// 1964 Copyright (C) 1999-2004 Joel Middendorf, <schibo@emulation64.com>.  This
// program is free software;  you can redistribute it and/or modify it under the
// terms of the GNU  General Public  License as  published by  the Free Software
// Foundation; either version 2 of the License,  or (at your option)  any  later
// version.  This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
// details.  You should have received a copy of the GNU  General Public  License
// along with this program; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place  -  Suite  330,  Boston, MA  02111-1307,  USA. To contact the
// authors: email: schibo@emulation64.com, rice1964@yahoo.com

#include "../stdafx.h"

unsigned long		JumpTargets[100];
unsigned char		*RecompCode;
unsigned long		lCodeSize;

/*
 =======================================================================================================================
 =======================================================================================================================
 */

void SetTranslator(unsigned char *Code, unsigned long Pos, unsigned long Size)
{
	RecompCode = Code;
	compilerstatus.lCodePosition = Pos;
	lCodeSize = Size;
    
    //Uncomment the next line to debug the overrun. This is for Debugging only!!
    //lCodeSize = 65536*16;
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void SetTarget(unsigned char bIndex)
{
	char	bPosition;

	bPosition = (char)((compilerstatus.lCodePosition - JumpTargets[bIndex]) & 0xFF);
    if (((_int32)JumpTargets[bIndex]) <= 0)
  {
//        __asm int 3;
    }
    else
	RecompCode[JumpTargets[bIndex] - 1] = bPosition;
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void DynaBufferOverrun(void)
{
	compilerstatus.DynaBufferOverError = TRUE;
	TRACE0("Dyna buffer overrun");
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void WC8(unsigned int bValue)
{
	if((compilerstatus.lCodePosition + 100000) > lCodeSize) 
		DynaBufferOverrun();

    RecompCode[compilerstatus.lCodePosition] = (unsigned __int8)bValue;
	compilerstatus.lCodePosition++;
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void WC16(unsigned int wValue)
{
	if((compilerstatus.lCodePosition + 100000) > lCodeSize) 
		DynaBufferOverrun();

	(*((unsigned _int16 *) (&RecompCode[compilerstatus.lCodePosition])) = (unsigned _int16) (wValue));
	compilerstatus.lCodePosition += 2;
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void WC32(unsigned long dwValue)
{
    if((compilerstatus.lCodePosition + 100000) > lCodeSize) 
    	DynaBufferOverrun();

    (*((unsigned _int32 *) (&RecompCode[compilerstatus.lCodePosition])) = (unsigned _int32) (dwValue));
	compilerstatus.lCodePosition += 4;
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void ADD_Reg2ToReg1(unsigned int Reg1, unsigned int Reg2)
{
	WC8(0x03);
	WC8( (0xC0 | (Reg1 << 3) | Reg2));
}

void SBB_Reg2FromReg1(unsigned int Reg1, unsigned int Reg2)
{
	WC8(0x1B);
	WC8( (0xC0 | (Reg1 << 3) | Reg2));
}


/*
 =======================================================================================================================
 CMOV is for Pentium Pro and above
 =======================================================================================================================
 */
void CMOVcc_Reg2ToReg1(unsigned char ConditionCode, unsigned char Reg1, unsigned char Reg2)
{
	WC8( 0x0F);
	WC8( (0x40 | ConditionCode));
	WC8( (0xC0 | (Reg1 << 3) | Reg2));
}


/*
 =======================================================================================================================
 =======================================================================================================================
 */
void ADD_MemoryToReg(unsigned int Reg, unsigned int ModRM, unsigned int Address)
{
    WC8(0x03);
	Encode_Slash_R(Reg, ModRM, Address);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void SUB_MemoryToReg(unsigned int Reg, unsigned int ModRM, unsigned int Address)
{
    WC8(0x2B);
	Encode_Slash_R(Reg, ModRM, Address);
}

void SUB_ImmFromReg(unsigned int OperandSize, unsigned int Reg, unsigned int Data, unsigned int PreserveFlags)
{
    if((Data == 0)&&(!PreserveFlags)) return;

    if(OperandSize == 1)
	{
		if((Data < 128) || (Data >= (0xffffff80)))	// [-128 to 127] 
		{
			SUB_Imm8sxToReg(Reg, (unsigned char) Data, PreserveFlags);
			return;
		}
	}

	if(Reg == Reg_EAX)
	{
		WC8( (0x2C | OperandSize));	// SUB_ImmToEAX 
	}
	else
	{
		WC8( (0x80 | OperandSize));
		WC8( (0xE8 | Reg));
	}

	if(OperandSize == 0)
		WC8( Data);
	else
		WC32(Data);
}

/*
 =======================================================================================================================
    Danger: if Operand size == 0!. Fix! (Fortunately we never use 0 yet)
 =======================================================================================================================
 */
void ADD_ImmToReg(unsigned int Reg, unsigned int Data, unsigned int PreserveFlags)
{
    if((Data == 0)&&(!PreserveFlags)) return;

		if((Data < 128) || (Data >= (0xffffff80)))	// [-128 to 127] 
		{
			ADD_Imm8sxToReg(Reg, (unsigned char) Data);
			return;
		}

	if(Reg == Reg_EAX)
	{
		WC8(0x05);	// ADD_ImmToEAX 
	}
	else
	{
		WC8(0x81);
		WC8( (0xC0 | Reg));
	}

	WC32(Data);
}





/*
 =======================================================================================================================
 =======================================================================================================================
 */
void AND_ImmToEAX(unsigned int OperandSize, unsigned int Data)
{
	WC8( (0x24 | OperandSize));
	if(OperandSize == 0)
		WC8( Data);
	else
		WC32(Data);
}

/*
 =======================================================================================================================
    Be careful with operandsize = 0!. there is no esl, edl
 =======================================================================================================================
 */
void AND_ImmToReg(unsigned int Reg, unsigned int Data, unsigned int FlagsMatter)
{
    if((Data == 0xffffffff)&&(!FlagsMatter)) return;

		if((Data == 0)&&(!FlagsMatter))
		{
			XOR_Reg2ToReg1(Reg, Reg);
			return;
		}

		if((Data < 128) || (Data >= (0xffffff80)))	/* [-128 to 127] */
		{
			AND_Imm8sxToReg(Reg, (unsigned char) Data);
			return;
		}

	if(Reg == Reg_EAX)
	{
		AND_ImmToEAX(1, Data);
		return;
	}

	WC8(0x81);
	WC8( (0xE0 | Reg));
	WC32(Data);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void AND_ImmToMemory(unsigned long Address, unsigned long Data)
{
	if(Data == 0xffffffff) return;
	WC8( 0x81);
	WC8( 0x25);
	WC32(Address);
	WC32(Data);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void X86_CALL(unsigned long dwAddress)
{
	unsigned __int32	wTemp;

	wTemp = dwAddress - (unsigned __int32) (char *) &RecompCode[compilerstatus.lCodePosition] - 5;
	WC8(0xe8);
	WC32(wTemp);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void CALL_Reg(unsigned int Reg)
{
	WC8( 0xFF);
	WC8( (0xD0 | Reg));
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void CDQ(void)
{
	WC8( 0x99);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void CMP_Reg1WithReg2(unsigned int Reg1, unsigned int Reg2)
{
	WC8(0x39);
	WC8( (0xC0 | (Reg1 << 3) | Reg2));
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void CMP_Reg2WithReg1(unsigned int Reg1, unsigned int Reg2)
{
	WC8(0x3B);
	WC8( (0xC0 | (Reg1 << 3) | Reg2));
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void CMP_EAXWithImm(unsigned int OperandSize, unsigned int Data)
{
	WC8( (0x3C | OperandSize));
	WC32(Data);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void CMP_RegWithImm(unsigned int Reg, unsigned int Data)
{
	if(Data == 0)
		CMP_RegWith0(Reg); 

	if((Data < 128) || (Data >= (0xffffff80)))	// [-128 to 127] 
	{
		CMP_sImm8WithReg(1, Reg, (unsigned char) Data);
		return;
	}

	if(Reg == Reg_EAX)
	{
		CMP_EAXWithImm(1, Data);
		return;
	}

	WC8(0x81);
	WC8( (0xF8 | Reg));
	WC32(Data);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void CMP_RegWith0(unsigned int Reg)
{
	if(Reg == Reg_EAX)
	{
		TEST_EAXWithEAX();
		return;
	}

	TEST_Reg2WithReg1(Reg, Reg);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void CMP_MemoryWithImm(unsigned int dwAddress, unsigned int Data)
{
	WC8(0x81);
	WC8( 0x3D);
	WC32(dwAddress);
	WC32(Data);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void CMP_RegWithMemory(unsigned int Reg, unsigned int dwAddress)
{
	WC8(0x3B);
	WC8( (0x05 | (Reg << 3)));
	WC32(dwAddress);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void FABS(void)
{
	WC8(0xd9);
	WC8(0xe1);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void FADD_Memory(unsigned int OperandSize, unsigned int dwAddress)
{
	WC8( (0xD8 + OperandSize));
	WC8(0x05);
	WC32(dwAddress);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void FCOMP(unsigned char OperandSize, unsigned long dwAddress)
{
	WC8( (0xD8 + OperandSize));
	WC8(0x1D);
	WC32(dwAddress);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void FNSTSW(void)
{
	WC8(0xDF);
	WC8(0xE0);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void FDIV_Memory(unsigned char OperandSize, unsigned long dwAddress)
{
	WC8( (0xD8 + OperandSize));
	WC8(0x35);
	WC32(dwAddress);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void FISTP_Memory(unsigned char OperandSize, unsigned long dwAddress)
{
	WC8( (0xDB + OperandSize));
	
    if (OperandSize == FORMAT_QUAD)
    {
        WC8(0x05+(8*7));
	    WC32(dwAddress);
    }
    else
    {
        WC8(0x05+(8*3));
	    WC32(dwAddress);
    }
}


/*
 =======================================================================================================================
 =======================================================================================================================
 */
void FLD_Memory(unsigned char OperandSize, unsigned long dwAddress)
{
	WC8( (0xD9 + OperandSize));
	WC8(0x05);
	WC32(dwAddress);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void FLDCW_Memory(unsigned long dwAddress)
{
	WC8(0xd9);
	WC8(0x2d);
	WC32(dwAddress);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void FILD_Memory(unsigned char OperandSize, unsigned long dwAddress)
{
	WC8( (0xDB + OperandSize));
	
    if (OperandSize == FORMAT_QUAD)
        WC8(0x2D);
    else
        WC8(0x05);

	WC32(dwAddress);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void FMUL_Memory(unsigned char OperandSize, unsigned long dwAddress)
{
	WC8( (0xD8 + OperandSize));
	WC8(0x0d);
	WC32(dwAddress);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void FNEG(void)
{
	WC8(0xd9);
	WC8(0xe0);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void FRNDINT(void)
{
	WC8(0xD9);
	WC8(0xFC);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void FSQRT(void)
{
	WC8(0xd9);
	WC8(0xfa);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void FSTP_Memory(unsigned char OperandSize, unsigned long dwAddress)
{
	WC8( (0xd9 + OperandSize));
	WC8(0x1d);
	WC32(dwAddress);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void FSUB_Memory(unsigned char OperandSize, unsigned long dwAddress)
{
	WC8( (0xD8 + OperandSize));
	WC8(0x25);
	WC32(dwAddress);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void IMUL_EAXWithReg(unsigned int Reg)
{
	WC8(0xF7);
	WC8( (0xE8 | Reg));
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void IMUL_EAXWithMemory(unsigned int OperandSize, unsigned int Address)
{
	WC8( (0xF6 | OperandSize));
	WC8( (0x2D));
	WC32(Address);
}

/*
 =======================================================================================================================
    Incomplete..assumed: operandsize = 1
 =======================================================================================================================
 */
void DEC_Reg(unsigned int OperandSize, unsigned int Reg)
{
	
	if(OperandSize == 1)
	{
		WC8( (0x48 | Reg));
	}
	else
	{
		DisplayError("DEC: Incomplete");
	}
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void INC_Reg(unsigned int OperandSize, unsigned int Reg)
{
	if(OperandSize == 1)
	{
		WC8( (0x40 | Reg));
	}
	else
	{
		WC8(0xfe);
		WC8( (0xc0 | Reg));
	}
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void DIV_EAXWithReg(unsigned int OperandSize, unsigned int Reg)
{
	WC8( (0xF6 | OperandSize));
	WC8( (0xF0 | Reg));
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void IDIV_EAXWithReg(unsigned char OperandSize, unsigned char Reg)
{
	WC8( (0xF6 | OperandSize));
	WC8( (0xF8 | Reg));
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void Jcc(unsigned char ConditionCode, unsigned char Offset)
{
	WC8( (0x70 | ConditionCode));
	WC8( Offset);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void Jcc_auto(unsigned char ConditionCode, unsigned long Index)
{
	LOGGING_DYNA(LogDyna("	Jcc () to %i\n", Index);) 
	
	WC8( (0x70 | ConditionCode));
	WC8( 0x00);
	JumpTargets[Index] = compilerstatus.lCodePosition;
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
__inline void Jcc_Near_auto(unsigned char ConditionCode, unsigned long Index)
{
	LOGGING_DYNA(LogDyna("	Jcc () to %i\n", Index);) 
		
	WC8( (0x0F));
	WC8( (0x80 | ConditionCode));
	WC32(0x90909090);
	JumpTargets[Index] = compilerstatus.lCodePosition;
}

int Jcc_Near(unsigned char ConditionCode, unsigned long dwAddress)
{
	unsigned __int32	wTemp;

	wTemp = dwAddress - (unsigned __int32) (char *) &RecompCode[compilerstatus.lCodePosition] - 6;
    WC8( (0x0F));
	WC8( (0x80 | ConditionCode));
    WC32(wTemp);
    
    return (int)(&dyna_RecompCode[compilerstatus.lCodePosition] - 4);

}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void SetNearTarget(unsigned char bIndex)
{
	int wPosition;

	LOGGING_DYNA(LogDyna("j_point %i:\n", bIndex););


	wPosition = ((compilerstatus.lCodePosition - JumpTargets[bIndex]));
    if (((_int32)JumpTargets[bIndex]) <= 4)
    {
//        __asm int 3;
    }

//00445DBA 8B 0C 85 80 D5 45 00 mov         ecx,dword ptr [eax*4+45D580h] 
//00445DC1 8B 15 14 D7 45 00 mov         edx,dword ptr ds:[45D714h] 
//00445DC7 8B 45 F8         mov         eax,dword ptr [ebp-8] 
//00445DCA 89 44 0A FC      mov         dword ptr [edx+ecx-4],eax 
    else
	*(unsigned _int32 *) &RecompCode[JumpTargets[bIndex] - 4] = wPosition;
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void JMP_Short(unsigned char Offset)
{
	WC8( 0xEB);
	WC8( Offset);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void JMP_Short_auto(unsigned long Index)
{
	LOGGING_DYNA(LogDyna("	JMP_SHORT () to %i\n", Index);) WC8( 0xEB);
	WC8( 0x00);
	JumpTargets[Index] = compilerstatus.lCodePosition;
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void JMP_Long(unsigned long dwAddress)
{
	LOGGING_DYNA(LogDyna("	JMP_Long () to %08x\n", dwAddress);) 
	WC8(0xE9);
	WC32(dwAddress);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void JMP_FAR(unsigned long dwAddress)
{
	LOGGING_DYNA(LogDyna("	JMP () to %08x\n", dwAddress);) 
	WC8(0xFF);
	WC8(0x25);
	WC32(dwAddress);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void MOV_Reg2ToReg1(unsigned int Reg1, unsigned int Reg2)
{
	if(Reg1 == Reg2) return;
	WC8( 0x8B);
	WC8( (0xC0 | (Reg1 << 3) | Reg2));
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void MOV_MemoryToReg(unsigned int Reg, unsigned int ModRM, unsigned int Address)
{
    if (ModRM  == (0xC0|Reg))
    {
        return;
    }


    
    if((Reg == Reg_EAX) && (ModRM == ModRM_disp32))
	{
		MOV_MemoryToEAX(Address);
		return;
	}

	WC8(0x8B);
	Encode_Slash_R(Reg, ModRM, Address);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void MOV_ModRMToReg(unsigned int Reg, unsigned int ModRM)
{
	if(Reg == Reg_ESP || Reg == Reg_EBP)
		DisplayError("Fix me in function MOV_ModRMToReg(), does not support ESP and EBP");
	WC8(0x8B);
	WC8( ((Reg << 3) | ModRM));
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void MOV_RegToModRM(unsigned int OperandSize, unsigned int Reg, unsigned int ModRM)
{
	if(Reg == Reg_ESP || Reg == Reg_EBP)
		DisplayError("Fix me in function MOV_ModRMToReg(), does not support ESP and EBP");
	WC8( (0x88 | OperandSize));
	WC8( ((Reg << 3) | ModRM));
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void MOVSX_Memory8ToReg(unsigned int Reg, unsigned int ModRM, unsigned int Address)
{
	WC8(0x0F);
	WC8(0xBE);
	WC8( (ModRM | (Reg << 3)));
	if(Address != 0) WC32(Address);
}

void MOVSX_Memory16ToReg(unsigned int Reg, unsigned int ModRM, unsigned int Address)
{
	WC8(0x0F);
	WC8(0xBF);
	WC8( (ModRM | (Reg << 3)));
	if(Address != 0) WC32(Address);
}


/*
 =======================================================================================================================
 =======================================================================================================================
 */
void MOVZX_Memory8ToReg(unsigned int Reg, unsigned int ModRM, unsigned int Address)
{
	WC8(0x0F);
	WC8(0xB6);
	WC8( (ModRM | (Reg << 3)));
	if(Address != 0) WC32(Address);
}

void MOVZX_Memory16ToReg(unsigned int Reg, unsigned int ModRM, unsigned int Address)
{
	WC8(0x0F);
	WC8(0xB7);
	WC8( (ModRM | (Reg << 3)));
	if(Address != 0) WC32(Address);
}



/*
 =======================================================================================================================
 =======================================================================================================================
 */
void MOV_MemoryToEAX(unsigned int Address)
{
	WC8(0xA1);
	WC32(Address);
}

/*
 =======================================================================================================================
    1964 uses ebp as a ponter to the middle of the Mips GPR array in memory. ?    Address can also represent displacement.
 =======================================================================================================================
 */
void MOV_RegToMemory(unsigned int OperandSize, unsigned int Reg, unsigned int ModRM, unsigned int Address)
{
    
    if((Reg == Reg_EAX) && (ModRM == ModRM_disp32))
	{
		MOV_EAXToMemory(OperandSize, Address);
		return;
	}

	WC8( (0x88 | OperandSize));
	Encode_Slash_R(Reg, ModRM, Address);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void MOV_EAXToMemory(unsigned int OperandSize, unsigned int Address)
{
	WC8( (0xA2 | OperandSize));
	WC32(Address);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void MOV_ImmToReg(unsigned int Reg, unsigned int Data)
{
	if(Data == 0)
	{
		XOR_Reg2ToReg1(Reg, Reg);
		return;
	}

	if (Data == -1)
	{
		OR_ImmToReg(Reg, 0xFFFFFFFF, 0);
		return;
	}

	WC8(0xB8 | Reg);
	WC32(Data);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void MOV_ImmToMemory(unsigned char OperandSize, unsigned char ModRM, unsigned long Address, unsigned long Data)
{
	WC8( (0xC6 | OperandSize));
	if((ModRM >= ModRM_disp8_EAX) && (ModRM <= ModRM_disp8_EDI))
	{
		if((Address == 0) && (ModRM != ModRM_disp8_EBP) && (ModRM != ModRM_disp8_SIB)) 
			ModRM -= 0x40;
		WC8( (ModRM));
		if((Address == 0) && (ModRM == ModRM_EBP))
			WC8(0x28);
		else
			WC8( Address);
	}
	else
	{
		WC8( (ModRM));
		if(Address != 0) WC32(Address);
	}

	if(OperandSize == 1)
		WC32(Data);
	else
		WC8((unsigned __int8) (Data));
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void MUL_EAXWithReg(unsigned int Reg)
{
	WC8(0xF7);
	WC8( (0xE0 | Reg));
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void MUL_EAXWithMemory(unsigned int OperandSize, unsigned int Address)
{
	WC8( (0xF6 | OperandSize));
	WC8( (0x25));
	WC32(Address);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void NEG_Reg(unsigned char OperandSize, unsigned char Reg)
{
	WC8( (0xF6 | OperandSize));
	WC8( (0xD8 | Reg));
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void NOT_Reg(unsigned int OperandSize, unsigned int Reg)
{
	WC8( (0xF6 | OperandSize));
	WC8( (0xD0 | Reg));
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void NOP(void)
{
	WC8( 0x90);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void OR_ImmToEAX(unsigned int OperandSize, unsigned int Data)
{
	WC8( (0x0C | OperandSize));
	if(OperandSize == 0)
		WC8( Data);
	else
		WC32(Data);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void OR_ImmToReg(unsigned int Reg, unsigned int Data, unsigned int FlagsMatter)
{
	if((Data == 0)&&(!FlagsMatter)) return;

	if((Data < 128) || (Data >= (0xffffff80)))	/* [-128 to 127] */
	{
		OR_ShortToReg(Reg, Data);
		return;
	}

	if(Reg == Reg_EAX)
	{
		OR_ImmToEAX(1, Data);
		return;
	}

	WC8(0x81);
	WC8( (0xC8 | Reg));
	WC32(Data);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void OR_RegToMemory(unsigned char OperandSize, unsigned char Reg, unsigned char ModRM, unsigned long Address)
{
	WC8( (0x0A | OperandSize));
	Encode_Slash_R(Reg, ModRM, Address);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void POP_RegFromStack(unsigned int Reg)
{
	WC8( (0x58 | Reg));
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void POPA(void)
{
	WC8( 0x66);
	WC8( 0x61);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void POPAD(void)
{
	WC8( 0x61);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void PUSH_RegToStack(unsigned int Reg)
{
	WC8( (0x50 | Reg));
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void PUSH_WordToStack(unsigned __int32 wWord)
{
	WC8(0x68);
	WC32(wWord);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void PUSHA(void)
{
	WC8( 0x66);
	WC8( 0x60);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void PUSHAD(void)
{
	WC8( 0x60);
}

void RDTSC(void)
{
	WC16(0x310f);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void RET(void)
{
	WC8( 0xC3);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void SAHF(void)
{
	WC8(0x9e);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void SETcc_Reg(unsigned int ConditionCode, unsigned int Reg)
{
	WC8( 0x0F);
	WC8( (0x90 | ConditionCode));
	WC8( (0xC0 | Reg));
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void SAR_RegByCL(unsigned int Reg)
{
	WC8(0xD3);
	WC8( (0xF8 | Reg));
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void SHL_RegByImm(unsigned int Reg, unsigned int Data)
{
	if(Data == 0) return;
	if(Data == 1)
	{
		ADD_Reg2ToReg1(Reg, Reg);
		return;
	}

	if(Data == 2)
	{
		/* lea reg, [reg*4] */
		WC8(0x8D);
		WC8((uint8) (0x04 | (Reg << 3)));
		WC8((uint8) (0x85 | (Reg << 3)));
		WC32(0x00);
		return;
	}

	if(Data == 3)
	{
		/* lea reg, [reg*8] */
		WC8(0x8D);
		WC8((uint8) (0x04 | (Reg << 3)));
		WC8((uint8) (0xC5 | (Reg << 3)));
		WC32(0x00);
		return;
	}

	WC8(0xC1);
	WC8( (0xE0 | Reg));
	WC8( Data);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void SHR_RegByImm(unsigned int Reg, unsigned int Data)
{
	if(Data == 0) return;
	if(Data == 1)
	{
		SHR_RegBy1(Reg);
		return;
	}

	WC8(0xC1);
	WC8( (0xE8 | Reg));
	WC8( Data);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void SAR_RegByImm(unsigned int Reg, unsigned int Data)
{
	if(Data == 0) return;
	if(Data == 1)
	{
		SAR_RegBy1(Reg);
		return;
	}

	WC8(0xC1);
	WC8( (0xF8 | Reg));
	WC8( Data);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void SHR_RegBy1(unsigned int Reg)
{
	WC8(0xD1);
	WC8( (0xE8 | Reg));
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void SAR_RegBy1(unsigned char Reg)
{
	WC8(0xD1);
	WC8( (0xF8 | Reg));
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void SHL_RegByCL(unsigned int Reg)
{
	WC8(0xD3);
	WC8( (0xE0 | Reg));
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void SHR_RegByCL(unsigned int Reg)
{
	WC8(0xD3);
	WC8( (0xE8 | Reg));
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void SUB_Reg1OfReg2(unsigned int Reg1, unsigned int Reg2)
{
	WC8(0x29);
	WC8( (0xC0 | (Reg1 << 3) | Reg2));
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void DEC_Memory(unsigned char OperandSize, unsigned long Address)
{

	WC8( (0xFE | OperandSize));
	WC8(0x0D);	/* Disp32 */
	WC32(Address);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void ADD_ImmToMemory(unsigned long Address, unsigned long Data)
{
//    if (Data == -1) {DEC_Memory(1, Address); return;} //not worth the trouble.

		if((Data < 128) || (Data >= (0xffffff80)))	/* [-128 to 127] */
		{
            WC8( 0x83);
        	WC8( 0x05);
        	WC32(Address);
            WC8( Data);
        }
        else
        {
            WC8( 0x81);
        	WC8( 0x05);
        	WC32(Address);
        	WC32((unsigned long) (Data));
        }
}

/*
 =======================================================================================================================
    Assumed, Operand size = 1
 =======================================================================================================================
 */
void SUB_ImmToMemory(unsigned long Address, unsigned long Data)
{
		if((Data < 128) || (Data >= (0xffffff80)))	/* [-128 to 127] */
		{
            WC8( 0x83);
        	WC8( 0x2D);
        	WC32(Address);
            WC8( Data);
        }
        else
        {
            WC8( 0x81);
        	WC8( 0x2D);
        	WC32(Address);
        	WC32((unsigned long) (Data));
        }
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
__inline void TEST_ImmWithMemory(unsigned long dwAddress, unsigned long Value)
{
	WC8(0xf7);
	WC8(0x05);
	WC32(dwAddress);
	WC32(Value);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void TEST_EAXWithEAX(void)
{
	WC8(0x85);
	WC8(0xc0);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void TEST_Reg2WithReg1(unsigned char Reg1, unsigned char Reg2)
{
	if(Reg2 == Reg1)
	{
		if
		(Reg1 == Reg_EAX)
		{
			TEST_EAXWithEAX();
		}
		else
		{
			//ex: AND ecx, ecx (faster)
			//Do not call AND_Reg2ToReg1() because it is designed to return
			//when the operands are the same
			WC8(0x23);
			WC8( (0xC0 | (Reg1 << 3) | Reg2));
		}
	}
	else
	{
		WC8(0x85);
		WC8( (0xC0 | (Reg1 << 3) | Reg2));
	}
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void XOR_ImmToEAX(unsigned long Data)
{
	WC8(0x35);
	WC32(Data);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void XOR_Reg2ToReg1(unsigned int Reg1, unsigned int Reg2)
{
    WC8(0x33);
    WC8( (0xC0 | (Reg1 << 3) | Reg2));
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void XOR_ImmToReg(unsigned int Reg, unsigned int Data, unsigned int FlagsMatter)
{
	if((Data == 0)&&(!FlagsMatter)) return;

	if((Data < 128) || (Data >= (0xffffff80)))	/* [-128 to 127] */
	{
		XOR_ShortToReg(Reg, (unsigned char) Data);
		return;
	}

	if(Reg == Reg_EAX)
	{
		XOR_ImmToEAX(Data);
		return;
	}

	/* Normal execution */
	WC8(0x81);
	WC8( (0xF0 | Reg));
	WC32(Data);
}

/*
 =======================================================================================================================
    When OperandSize is 0, this doesn't sign extend.
 =======================================================================================================================
 */
void OR_ShortToReg(unsigned int Reg, unsigned int Data)
{
	WC8(0x83);
	WC8( (0xC8 | Reg));
	WC8( Data);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void XOR_ShortToReg(unsigned int Reg, unsigned int Data)
{
	WC8(0x83);
	WC8( (0xF0 | Reg));
	WC8( Data);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void AND_Reg2ToReg1(unsigned int Reg1, unsigned int Reg2)
{
	if(Reg2 == Reg1) return;	/* Note: for testing, use TEST. */
	WC8(0x23);
	WC8( (0xC0 | (Reg1 << 3) | Reg2));
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void OR_Reg2ToReg1(unsigned int Reg1, unsigned int Reg2)
{
	if(Reg2 == Reg1) return;
	WC8(0x0B);
	WC8( (0xC0 | (Reg1 << 3) | Reg2));
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void ADD_Imm8sxToReg(unsigned int Reg, unsigned char Data)
{
//    if (Data == 1) {INC_Reg(1, Reg); return;}
//    if (Data == 0xFF) {DEC_Reg(1, Reg); return;}
    
	WC8( (0x83));
	WC8( (0xC0 | Reg));
	WC8( Data);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void SUB_Imm8sxToReg(unsigned int Reg, unsigned char Data, int FlagsMatter)
{
    if (!FlagsMatter)
    {
        if (Data == 0xFF) {INC_Reg(1, Reg); return;}
        if (Data == 1) {DEC_Reg(1, Reg); return;}
    }

	WC8(0x83);
	WC8( (0xE8 | Reg));
	WC8( Data);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void Calculate_ModRM_Byte_Via_Slash_Digit(int SlashDigit)
{
	x86params.ModRM |= (SlashDigit << 3);
}


/*
 =======================================================================================================================
 =======================================================================================================================
 */
void ROL_RegByImm(unsigned int Reg, unsigned int Data)
{
	WC8(0xC1);
	x86params.ModRM = 0xC0 | Reg;
	Calculate_ModRM_Byte_Via_Slash_Digit(0);
	WC8(x86params.ModRM);
	WC8(Data);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void AND_Imm8sxToMemory(unsigned int Data, unsigned int Address)
{
	WC8(0x83);
	Calculate_ModRM_Byte_Via_Slash_Digit(4);
	WC8( (x86params.ModRM));
	WC8( Address);
	WC8( Data);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void AND_Imm8sxToReg(unsigned int Reg, unsigned int Data)
{
	WC8(0x83);
	WC8(0xE0 | Reg);
	WC8(Data);
}


/*
 =======================================================================================================================
 =======================================================================================================================
 */
void CMP_sImm8WithReg(unsigned int OperandSize, unsigned int Reg, unsigned int Data)
{
	WC8( (0x83));
	WC8( (0xF8 | Reg));
	WC8( Data);
}

/*
 =======================================================================================================================
    Encoders ?    1964 uses ebp as a ponter to the middle of the Mips GPR array in memory.
 =======================================================================================================================
 */
void Encode_Slash_R(unsigned int Reg, unsigned int ModRM, unsigned int Address)	/* so-named for the /r mnemonic in
																					 * Intel x86 docs */
{
	if((ModRM >= ModRM_disp8_EAX) && (ModRM <= ModRM_disp8_EDI))
	{
		WC8( (ModRM | (Reg << 3)));
		WC8( Address);
	}
	else if((ModRM >= ModRM_disp32_EAX) && (ModRM <= ModRM_disp32_EDI))
	{
		if(Address == 0)
		{
			ModRM -= ModRM_disp32_EAX;
			WC8( (ModRM | (Reg << 3)));
		}
		else
		{
			WC8( (ModRM | (Reg << 3)));
			WC32(Address);
		}
	}
	else
	{
		WC8( (ModRM | (Reg << 3)));
		if(Address != 0) WC32(Address);
	}
}

void INT3()
{
    WC8(0xCC);
}